using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Comteck.Utils;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraTreeList.Columns;

namespace Comteck.Winforms.Infrastructure {
  /// <summary>
  /// 主要针对下拉框绑定的公用方法，请勿在此做其他控件的绑定
  /// </summary>
  public static partial class BindHelper {

    /// <summary>
    /// 下拉框的最低高度
    /// </summary>
    private static int _Default_Edit_Min_Height = 126;
    private static int _Default_Edit_Max_Height = 200;

    /// <summary>
    /// 绑定下拉框控件
    /// </summary>
    /// <param name="control"></param>
    /// <param name="options">绑定选项</param>
    /// <param name="dataList">数据源</param>
    public static void Bind(object control, BindHelperOption options, dynamic dataList) {
      void action() {
        BindInner(control, options, dataList);
      }
      
      if (control is Control winformControl && options.IsAsync) {
        winformControl.InvokeMethodSync(action);
      } else {
        action();
      }
    }

    /// <summary>
    /// LookUpEdit,RepositoryItemLookUpEdit, -- 暂时不予考虑
    /// CheckedComboBoxEdit,RepositoryItemCheckedComboBoxEdit -- ok
    /// TreeListLookUpEdit,RepositoryItemTreeListLookUpEdit -- ok
    /// GridLookUpEdit -- ok
    /// </summary>
    /// <param name="control"></param>
    /// <param name="dataList"></param>
    /// <param name="options"></param>
    private static void BindInner(object control, BindHelperOption options, dynamic dataList) {
      if (control is LookUpEdit lookUpEdit) {
        lookUpEdit.Properties.ValueMember = options.ValueMember;
        lookUpEdit.Properties.DisplayMember = options.DisplayMember;
        lookUpEdit.Properties.BestFitMode = BestFitMode.BestFitResizePopup;
      } else if (control is GridLookUpEdit gridLookUp) {
        // 显示列和值列
        gridLookUp.Properties.ValueMember = options.ValueMember;
        gridLookUp.Properties.DisplayMember = options.DisplayMember;
        gridLookUp.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.True;
        gridLookUp.Properties.PopupFilterMode = PopupFilterMode.Contains;
        //gridLookUp.Properties.TextEditStyle = TextEditStyles.Standard;
        gridLookUp.Properties.TextEditStyle = options.TextEditStyle;
        //gridLookUp.KeyDown += BaseEdit_KeyDown;
        gridLookUp.Properties.NullText = string.Empty;
        gridLookUp.Properties.NullValuePrompt = options.NullValuePrompt;
        gridLookUp.Properties.AutoComplete = true;
        gridLookUp.Properties.ImmediatePopup = true;
        gridLookUp.Properties.PopupSizeable = true;

        // 添加显示列
        var gridView = gridLookUp.Properties.View;

        gridView.Columns.Clear();
        gridView.Columns.AddRange(CreateGridColumns(options.BindColumnOptions));

        // 加入Format格式功能
        foreach (var bindColumnOptions in options.BindColumnOptions.Where(x => x.FormatString != null).ToList()) {
          gridView.Columns[bindColumnOptions.FieldName].DisplayFormat.FormatType = bindColumnOptions.FormatType;
          gridView.Columns[bindColumnOptions.FieldName].DisplayFormat.FormatString = bindColumnOptions.FormatString;
        }

        gridView.FocusRectStyle = DevExpress.XtraGrid.Views.Grid.DrawFocusRectStyle.RowFocus;
        gridView.GroupCount = 1;
        gridView.OptionsBehavior.AllowPixelScrolling = DevExpress.Utils.DefaultBoolean.Default;
        gridView.OptionsBehavior.AutoExpandAllGroups = true;
        gridView.OptionsSelection.EnableAppearanceFocusedCell = false;
        gridView.OptionsView.ShowAutoFilterRow = false;
        gridView.OptionsView.ShowGroupPanel = false;

        //gridview.OptionsView.ColumnAutoWidth = true;
        //gridview.HorzScrollVisibility = DevExpress.XtraGrid.Views.Base.ScrollVisibility.Always;

        gridLookUp.Properties.DataSource = dataList;
        if (options.EditValue != null) {
          gridLookUp.EditValue = options.EditValue;//不给默认值。启用MVVM的话 导致执行重复的editvaluechanged事件
        }

        var width = options.BindColumnOptions.Where(x => x.Visible).Sum(x => x.Width) + 60;
        //gridLookUp.Properties.PopupFormSize = new System.Drawing.Size(width, 0);

        // height有下限，设置了一个小于126的数字，实际效果是126
        // 记录超过4行才用200的高度
        var count = (dataList as IEnumerable<dynamic>)?.Count() ?? 0;
        var height = 32 * count;
        gridLookUp.Properties.PopupFormSize = new System.Drawing.Size(width, Math.Min(Math.Max(height, _Default_Edit_Min_Height), _Default_Edit_Max_Height));
        gridLookUp.Properties.BestFitMode = BestFitMode.BestFitResizePopup;
        //gridView.OptionsView.BestFitMode = DevExpress.XtraGrid.Views.Grid.GridBestFitMode.Full;
        //gridView.BestFitColumns();
      } else if (control is RepositoryItemGridLookUpEdit repositoryGridLookUpEdit) {
        repositoryGridLookUpEdit.ValueMember = options.ValueMember;
        repositoryGridLookUpEdit.DisplayMember = options.DisplayMember;
        repositoryGridLookUpEdit.AllowNullInput = DevExpress.Utils.DefaultBoolean.True;
        repositoryGridLookUpEdit.PopupFilterMode = PopupFilterMode.Contains;
        //repositoryGridLookUpEdit.TextEditStyle = TextEditStyles.Standard;  
        repositoryGridLookUpEdit.TextEditStyle = options.TextEditStyle;
        repositoryGridLookUpEdit.KeyDown += BaseEdit_KeyDown;
        repositoryGridLookUpEdit.NullText = string.Empty;
        repositoryGridLookUpEdit.NullValuePrompt = options.NullValuePrompt;
        repositoryGridLookUpEdit.ImmediatePopup = true;

        // 添加显示列
        var gridView = repositoryGridLookUpEdit.View;
        gridView.Columns.Clear();
        gridView.Columns.AddRange(CreateGridColumns(options.BindColumnOptions));

        // 加入Format格式功能
        foreach (var bindColumnOptions in options.BindColumnOptions.Where(x => x.FormatString != null).ToList()) {
          gridView.Columns[bindColumnOptions.FieldName].DisplayFormat.FormatType = bindColumnOptions.FormatType;
          gridView.Columns[bindColumnOptions.FieldName].DisplayFormat.FormatString = bindColumnOptions.FormatString;
        }

        gridView.FocusRectStyle = DevExpress.XtraGrid.Views.Grid.DrawFocusRectStyle.RowFocus;
        gridView.GroupCount = 1;
        gridView.OptionsBehavior.AllowPixelScrolling = DevExpress.Utils.DefaultBoolean.Default;
        gridView.OptionsBehavior.AutoExpandAllGroups = true;
        gridView.OptionsSelection.EnableAppearanceFocusedCell = false;
        gridView.OptionsView.ShowAutoFilterRow = false;
        gridView.OptionsView.ShowGroupPanel = false;

        repositoryGridLookUpEdit.DataSource = dataList;

        // 匹配高度
        var width = options.BindColumnOptions.Sum(x => x.Width) + 60;
        repositoryGridLookUpEdit.PopupFormSize = new System.Drawing.Size(width, Math.Min(Math.Max(repositoryGridLookUpEdit.PopupFormSize.Height, _Default_Edit_Min_Height), _Default_Edit_Max_Height));
        repositoryGridLookUpEdit.BestFitMode = BestFitMode.BestFitResizePopup;
      } else if (control is CheckedComboBoxEdit checkedComboBox) {
        // 填充数据
        checkedComboBox.SetEditValue(options.EditValue);
        checkedComboBox.Properties.ValueMember = options.ValueMember;
        checkedComboBox.Properties.DisplayMember = options.DisplayMember;
        checkedComboBox.Properties.DataSource = dataList;
      } else if (control is RepositoryItemCheckedComboBoxEdit repositoryCheckedComboBox) {
        // 填充数据
        repositoryCheckedComboBox.ValueMember = options.ValueMember;
        repositoryCheckedComboBox.DisplayMember = options.DisplayMember;
        repositoryCheckedComboBox.DataSource = dataList;
      } else if (control is TreeListLookUpEdit treeListLookUp) {
        // 树形参数
        treeListLookUp.Properties.TreeList.KeyFieldName = options.KeyFieldName;
        treeListLookUp.Properties.TreeList.ParentFieldName = options.ParentFieldName;
        treeListLookUp.Properties.TreeList.OptionsView.ShowAutoFilterRow = false; // 显示过滤行
        treeListLookUp.Properties.TreeList.OptionsBehavior.EnableFiltering = true; // 启用过滤
        treeListLookUp.Properties.TreeList.OptionsView.EnableAppearanceEvenRow = true;
        treeListLookUp.Properties.TreeList.OptionsView.EnableAppearanceOddRow = true;
                                                   
        // 添加树形列
        treeListLookUp.Properties.TreeList.Columns.Clear();
        treeListLookUp.Properties.TreeList.Columns.AddRange(CreateTreeListColumns(options.BindColumnOptions));
        
        // 数据源
        treeListLookUp.Properties.ValueMember = options.ValueMember;
        treeListLookUp.Properties.DisplayMember = options.DisplayMember;

        treeListLookUp.Properties.TextEditStyle = TextEditStyles.Standard;
        treeListLookUp.Properties.AllowNullInput = DevExpress.Utils.DefaultBoolean.True;
        treeListLookUp.Properties.NullText = string.Empty;
        treeListLookUp.Properties.NullValuePrompt = options.NullValuePrompt;
        
        treeListLookUp.Properties.AutoComplete = true;
        treeListLookUp.Properties.ImmediatePopup = true;
        treeListLookUp.Properties.PopupSizeable = true;
        treeListLookUp.Properties.AutoExpandAllNodes = false;
        //treeListLookUp.Properties.PopupFormSize = new System.Drawing.Size(0, 340);
        treeListLookUp.Properties.PopupFilterMode = PopupFilterMode.Contains;
        treeListLookUp.Properties.DataSource = dataList;
        if (options.EditValue != null) {
          treeListLookUp.EditValue = options.EditValue;
        }

        // 匹配高度
        treeListLookUp.Properties.BestFitMode = BestFitMode.BestFitResizePopup;
        //treeListLookUp.Properties.TreeList.CollapseAll(); // 默认不展开
      } else if (control is RepositoryItemTreeListLookUpEdit repositoryTreeListLookUp) {
        // 树形参数
        repositoryTreeListLookUp.TreeList.KeyFieldName = options.KeyFieldName;
        repositoryTreeListLookUp.TreeList.ParentFieldName = options.ParentFieldName;
        repositoryTreeListLookUp.TreeList.OptionsView.ShowAutoFilterRow = false; // 显示过滤行
        repositoryTreeListLookUp.TreeList.OptionsBehavior.EnableFiltering = true; // 启用过滤
        repositoryTreeListLookUp.TreeList.OptionsView.EnableAppearanceEvenRow = true;
        repositoryTreeListLookUp.TreeList.OptionsView.EnableAppearanceOddRow = true;
        repositoryTreeListLookUp.KeyDown += BaseEdit_KeyDown;

        // 添加树形列
        repositoryTreeListLookUp.TreeList.Columns.Clear();
        repositoryTreeListLookUp.TreeList.Columns.AddRange(CreateTreeListColumns(options.BindColumnOptions));

        // 数据源
        repositoryTreeListLookUp.ValueMember = options.ValueMember;
        repositoryTreeListLookUp.DisplayMember = options.DisplayMember;
        repositoryTreeListLookUp.TextEditStyle = TextEditStyles.Standard;
        repositoryTreeListLookUp.AllowNullInput = DevExpress.Utils.DefaultBoolean.True;
        repositoryTreeListLookUp.NullText = string.Empty;

        repositoryTreeListLookUp.AutoComplete = true;
        repositoryTreeListLookUp.ImmediatePopup = true;
        repositoryTreeListLookUp.PopupSizeable = true;
        repositoryTreeListLookUp.AutoExpandAllNodes = false;

        repositoryTreeListLookUp.BeginUpdate();
        repositoryTreeListLookUp.DataSource = dataList;
        repositoryTreeListLookUp.BestFitMode = BestFitMode.BestFitResizePopup;
        repositoryTreeListLookUp.EndUpdate();
      } else if (control is RepositoryItemLookUpEdit repositoryItemLookUpEdit) {
        // 填充数据
        repositoryItemLookUpEdit.ValueMember = options.ValueMember;
        repositoryItemLookUpEdit.DisplayMember = options.DisplayMember;
        repositoryItemLookUpEdit.DataSource = dataList;
        repositoryItemLookUpEdit.TextEditStyle = TextEditStyles.Standard;

        // 添加默认列
        if (repositoryItemLookUpEdit.Columns.Count == 0) {
          repositoryItemLookUpEdit.Columns.AddRange(CreateLookUpColumnInfo(options.BindColumnOptions));
        }
      }
    }

    /// <summary>
    /// 按下回车键清除选定的内容
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public static void BaseEdit_KeyDown(object sender, KeyEventArgs e) {
      if (e.KeyCode == Keys.Delete) {
        var control = sender as BaseEdit;

        control.EditValue = null;
        e.Handled = true;
      } else if (e.KeyCode == Keys.Back) {
        //var control = sender as BaseEdit;

        //if (control.EditValue.Is(EnumValidateType.Null)) {
        //  control.EditValue = null;
        //  e.Handled = true;
        //}

      }
    }

    /// <summary>
    /// 构建 GridView的列
    /// </summary>
    /// <param name="columnOptions"></param>
    /// <returns></returns>
    public static GridColumn[] CreateGridColumns(List<BindColumnOption> columnOptions) {
      if (columnOptions == null) {
        return null;
      }

      var result = columnOptions.Select(x => new GridColumn() {
        Width = x.Width,
        Caption = x.Caption,
        FieldName = x.FieldName,
        Name = $"sub_{x.FieldName}",
        Visible = x.Visible,
        ColumnEdit = x.ColumnEdit
        //VisibleIndex = 1
      });
      return result.ToArray();
    }

    /// <summary>
    /// 构建 TreeList的列
    /// </summary>
    /// <param name="columnOptions"></param>
    /// <returns></returns>
    private static TreeListColumn[] CreateTreeListColumns(List<BindColumnOption> columnOptions) {
      if (columnOptions == null) {
        return null;
      }

      var result = columnOptions.Select(x => new TreeListColumn() {
        Width = x.Width,
        Caption = x.Caption,
        FieldName = x.FieldName,
        Name = $"sub_{x.FieldName}",
        Visible = x.Visible,
        //VisibleIndex = 1
      });

      return result.ToArray();
    }

    /// <summary>
    /// 构建 TreeList的列
    /// </summary>
    /// <param name="columnOptions"></param>
    /// <returns></returns>
    public static LookUpColumnInfo[] CreateLookUpColumnInfo(List<BindColumnOption> columnOptions) {
      if (columnOptions == null) {
        return null;
      }

      var result = columnOptions.Select(x => new LookUpColumnInfo() {
        Width = x.Width,
        Caption = x.Caption,
        FieldName = x.FieldName,
        Visible = x.Visible,
        //VisibleIndex = 1
      });

      return result.ToArray();
    }

    /// <summary>
    /// 
    /// </summary>
    private static string nameValueEntityIds = new List<string> { nameof(NameValueEntity.Id), nameof(NameValueEntity.Name) }.JoinAsString(",");

    /// <summary>
    /// 绑定枚举
    /// </summary>
    /// <typeparam name="E"></typeparam>
    /// <param name="control"></param>
    /// <param name="editValue"></param>
    public static void Bind<E>(object control, object editValue = null, Action<BindHelperOption> action = null) {
      var options = new BindHelperOption() {
        DisplayMember = nameof(NameValueEntity.Name),
        ValueMember = nameof(NameValueEntity.Id),
        NullValuePrompt = string.Empty,
        BindColumnOptions = new List<BindColumnOption>() {
          new BindColumnOption(){ Caption="编号",Width=60,FieldName=nameof(NameValueEntity.Id)},
          new BindColumnOption(){ Caption="名称",Width=140,FieldName=nameof(NameValueEntity.Name) }
        },
        EditValue = editValue,
        TextEditStyle = TextEditStyles.Standard,
      };
      action?.Invoke(options);
      var list = EnumHelper.ToObjList<E, NameValueEntity>(nameValueEntityIds);
      Bind(control, options, list);
    }

    /// <summary>
    /// 绑定枚举
    /// </summary>
    /// <typeparam name="TE"></typeparam>
    /// <param name="control"></param>
    /// <param name="editValue"></param>
    /// <param name="without">排除指定枚举</param>
    public static void BindWithoutArray<TE>(object control, object editValue = null,params int[] without) {
      var options = new BindHelperOption() {
        DisplayMember = nameof(NameValueEntity.Name),
        ValueMember = nameof(NameValueEntity.Id),
        NullValuePrompt = string.Empty,
        BindColumnOptions = new List<BindColumnOption>() {
          new BindColumnOption(){ Caption="编号",Width=60,FieldName=nameof(NameValueEntity.Id)},
          new BindColumnOption(){ Caption="名称",Width=140,FieldName=nameof(NameValueEntity.Name) }
        },
        EditValue = editValue
      };
      var list = EnumHelper.ToObjList<TE, NameValueEntity>(nameValueEntityIds);
      if (without != null) {
        list = list.Where(x => !without.Contains(x.Id)).ToList();
      }
      Bind(control, options, list);
    }

    /// <summary>
    /// 绑定枚举
    /// </summary>
    /// <typeparam name="TE"></typeparam>
    /// <param name="control"></param>
    /// <param name="editValue"></param>
    /// <param name="with">包含指定枚举</param>
    public static void BindWithArray<TE>(object control, object editValue = null, params int[] with) {
      var options = new BindHelperOption() {
        DisplayMember = nameof(NameValueEntity.Name),
        ValueMember = nameof(NameValueEntity.Id),
        NullValuePrompt = string.Empty,
        BindColumnOptions = new List<BindColumnOption>() {
          new BindColumnOption(){ Caption = "编号", Width = 60, FieldName = nameof(NameValueEntity.Id)},
          new BindColumnOption(){ Caption = "名称", Width = 140, FieldName = nameof(NameValueEntity.Name) }
        },
        EditValue = editValue
      };
      var list = EnumHelper.ToObjList<TE, NameValueEntity>(nameValueEntityIds);
      if (with != null) {
        list = list.Where(x => with.Contains(x.Id)).OrderBy(x => x.Id).ToList();
      }
      Bind(control, options, list);
    }

    /// <summary>
    /// 绑定枚举
    /// </summary>
    /// <typeparam name="TE"></typeparam>
    /// <param name="control"></param>
    /// <param name="editValue"></param>
    /// <param name="without">排除指定枚举</param>
    public static void BindDescriptionWithoutArray<TE>(object control, object editValue = null, params int[] without) {
      var options = new BindHelperOption() {
        DisplayMember = nameof(NameValueEntity.Name),
        ValueMember = nameof(NameValueEntity.Id),
        NullValuePrompt = string.Empty,
        BindColumnOptions = new List<BindColumnOption>() {
          new BindColumnOption(){ Caption="编号",Width=60,FieldName=nameof(NameValueEntity.Id)},
          new BindColumnOption(){ Caption="名称",Width=140,FieldName=nameof(NameValueEntity.Name) }
        },
        EditValue = editValue
      };
      var list = EnumHelper.ToObjList<TE, NameValueEntity>(nameValueEntityIds);
      if (without != null) {
        list = list.Where(x => !without.Contains(x.Id)).ToList();
      }
      Bind(control, options, list);
    }

    /// <summary>
    /// 绑定枚举 当前选中的值
    /// </summary>
    /// <typeparam name="E"></typeparam>
    /// <param name="control"></param>
    /// <param name="value"></param>
    public static void BindModel<E>(object control,int value) {
      var options = new BindHelperOption() {
        DisplayMember = nameof(NameValueEntity.Name),
        ValueMember = nameof(NameValueEntity.Id),
        NullValuePrompt = "请选择",
        BindColumnOptions = new List<BindColumnOption>() {
          new BindColumnOption(){ Caption="编号",Width=60,FieldName=nameof(NameValueEntity.Id)},
          new BindColumnOption(){ Caption="名称",Width=60,FieldName=nameof(NameValueEntity.Name) }
        }
      };
      var list = EnumHelper.ToObjListModel<E, NameValueEntity>(nameValueEntityIds, value);

      Bind(control, options, list);
    }

    /// <summary>
    /// 绑定枚举
    /// </summary>
    /// <typeparam name="E"></typeparam>
    /// <param name="control"></param>
    public static void BindByName<E>(object control) {
      var options = new BindHelperOption() {
        DisplayMember = nameof(NameValueEntity.Name),
        ValueMember = nameof(NameValueEntity.Name),
        NullValuePrompt = string.Empty,
        BindColumnOptions = new List<BindColumnOption>() {
          new BindColumnOption(){ Caption="编号",Width=60,FieldName=nameof(NameValueEntity.Id)},
          new BindColumnOption(){ Caption="名称",Width=200,FieldName=nameof(NameValueEntity.Name) }
        }
      };
      var list = EnumHelper.ToObjList<E, NameValueEntity>(nameValueEntityIds);

      Bind(control, options, list);
    }

    /// <summary>
    /// 绑定枚举
    /// </summary>
    /// <typeparam name="E"></typeparam>
    /// <param name="control"></param>
    public static void BindNameDescription<E>(object control, object editValue = null) {
      var options = new BindHelperOption() {
        DisplayMember = nameof(NameValueEntity.Name),
        ValueMember = nameof(NameValueEntity.Value),
        NullValuePrompt = string.Empty,
        BindColumnOptions = new List<BindColumnOption>() {
          new BindColumnOption(){ Caption="编号",Width=100,FieldName=nameof(NameValueEntity.Value)},
          new BindColumnOption(){ Caption="名称",Width=150,FieldName=nameof(NameValueEntity.Name) }
        },
        EditValue = editValue
      };

      var dicList = EnumHelper.ToNameDescription<E>();
      var list = (from d in dicList
                  select new NameValueEntity() {
                    Name = d.Value,
                    Value = d.Key
                  }).ToList();

      Bind(control, options, list);
    }
  }
}
